function openDB(name,versions) {
    const request=window.indexedDB.open(name,versions);
    return new Promise((r,j)=>{
        request.onerror = (event) => {
			j(event)
        };
        request.onsuccess = () => {
			r(request)
        };
    })
}
class IndexedDB{
	db=null
	name=""
	constructor(name="zijid"){
		this.name=name||"zijid"
	}
	async getDB(){
		if(!this.db){
			this.db=(await openDB(this.name)).result
			this.db.onclose=()=>{
				console.log("关闭");
			}
		}
		return this.db
	}
	createTable(table, config, indexs){
		return this.setKey(table, config, indexs)
	}
	isCreate(key){
		return this.getDB().then((db) => {
			return db.objectStoreNames.contains(key)
		
		})
	}
	/**
	 * 
	 * @param {String} table 
	 * @param {String} config.name - 数据表的名称
	 * @param {String} config.key - 主键的名称
	 * @param {Object} config.config - 数据表的配置对象
	 * @param {String} indexs[].name - 索引的名称
	 * @param {String} indexs[].key - 索引的键路径
	 * @param {Object} indexs[].config - 索引的配置
	 */
	async setKey(table, config, indexs) {
		const db=(await this.getDB())
		db.close()
		const upgradeDB = window.indexedDB.open(db.name, db.version + 1);
		return new Promise(async (resolve, reject) => {
			upgradeDB.onupgradeneeded = (event) => {
				const newDB = event.target.result;
				this.db=newDB
				try {
					if (newDB.objectStoreNames.contains(table)) {
						newDB.deleteObjectStore(table);
					}
					let objectStore=newDB.createObjectStore(table,config)
					if (Array.isArray(indexs)) {
						indexs.forEach((index) => {
							if (!objectStore.indexNames.contains(index.name)) {
								objectStore.createIndex(index.name, index.key || index.name, index.config||{...index});
							}
						});
					}
					// 在事务完成时关闭数据库
					objectStore.transaction.oncomplete = () => {
						resolve(true);
					};
					objectStore.transaction.onerror = () => {
					};
				} catch (err) {
					console.error(`err:`,err);
					reject(err);
				}
			};
		});
	}
	push(table,customerData,isUpdate=false){
		return new Promise(async r=>{
			const db=(await this.getDB())
			const transaction = db.transaction([table], "readwrite");
			const objectStore = transaction.objectStore(table);
			const errors = []
			const promiseArr=[]
			customerData.forEach(async (customer) => {
				let value,key
				if(typeof customer==="object" &&customer.value!==undefined){
					value=customer.value
					key=customer.key
				}else{
					value=customer
				}
				let request
				let fun
				if(isUpdate){
					fun=(value,key)=>{
						return this.put(table,value,key)
					}
				}else{
					fun=(...p)=>{
						return objectStore.add(...p)
					}
				}
				if(typeof value==="object" && objectStore.keyPath in value){
					request =await fun(value);
				}else{
					request = fun(value,key);
				}
				promiseArr.push(new Promise(async (r,j)=>{
					if(typeof request==="boolean"){
						r(request)
					}else{
						request.onsuccess = () => {
							r(true)
						};
						request.onerror = (err) => {
							const target=err.currentTarget||err.target
							errors.push("push("+(key||JSON.stringify(customerData))+")\n err:"+(target.error||target.error))
							j(err)
						};
					}
				}))
			})
			Promise.allSettled(promiseArr).then(res=>{
				if(errors.length){
					console.error(errors.join("\n\n"))
				}
				r(true)
			})
		})
	}
	add(table,value,key,isCreate=false) {
		return new Promise(async r=>{
			let db=(await this.getDB())
			let transaction
			try{
				transaction = db.transaction([table], "readwrite");
			}catch(err){
				this.close()
				db=(await this.getDB())
				transaction = db.transaction([table], "readwrite");
			}
			const objectStore = transaction.objectStore(table);
			let request
			if(typeof value==="object"&&objectStore.keyPath){
				if( !(objectStore.keyPath in value)&&key){
					value[objectStore.keyPath]=key
				}
				request = objectStore.add(value);
			}else{
				request = objectStore.add(value,key);
			}
			request.onsuccess = () => {
				r(true)
			};
			request.onerror = (err) => {
				if(isCreate){
					this.put(table,value,key).then(r)
				}else{
					console.error("add(",key||value,") err:",err.currentTarget.error);
					r(false)
				}
			};
		})
	}
	put(table,value,key){
		return new Promise(async r=>{
			let db=(await this.getDB())
			let transaction
			try{
				transaction = db.transaction([table], "readwrite");
			}catch(err){
				this.close()
				db=(await this.getDB())
				transaction = db.transaction([table], "readwrite");
			}

			const objectStore = transaction.objectStore(table);
			
			if(typeof value==="object"&&objectStore.keyPath){
				if( !(objectStore.keyPath in value)&&key){
					value[objectStore.keyPath]=key
				}
				objectStore.put(value)
			}else{
				objectStore.put(value,key)
			}
			transaction.oncomplete = () => {
				r(true);
			};
			transaction.onerror = (err) => {
				console.error(`err:`,err);
				r(true);
			};
			// customerData.forEach((customer) => {
			// 	const request = objectStore.add(customer);
			// 	request.onsuccess = () => {
			// 		// event.target.result === customer.ssn;
			// 	};
			// });
		})
	}
	delete(table,value){
		return new Promise( async r=>{
			const db=(await this.getDB())
			const objectStore=db
			.transaction([table], "readwrite")
			.objectStore(table)
			let pArr=[]
			let errors=[]
			if(Array.isArray(value)){
				value.forEach(i=>{
					pArr.push(new Promise((r,j)=>{
						const request=objectStore.delete(i)
						request.onsuccess = () => {
							r(true)
						};
						request.onerror = (err) => {
							console.error("delete(",table||value,") err:",err.currentTarget.error);
							j(false)
						};
					}))
				})
			}else{
				pArr.push(new Promise((r,j)=>{
					const request=objectStore.delete(value)
					request.onsuccess = () => {
						r(true)
					};
					request.onerror = (err) => {
						errors.push("delete("+(table||value)+") err:"+err.currentTarget.error);
						j(false)
					};
				}))
			}
			Promise.allSettled(pArr).then(res=>{
				if(errors.length){
					console.error(errors.join("\n\n"))
				}
				// console.error("push(",key,")err:",err.target.error);
				r(true)
			})			
		})
	}
	async deleteIndex(key,index){
		const temp_db=(await this.getDB())
		return new Promise( async r=>{
			let db=temp_db
			if(db.objectStoreNames.contains(key)){
				db.close()
				db=window.indexedDB.open(db.name,db.version+1);
				db.onupgradeneeded = (event) => {
					this.db=db.result
					try{
						const transaction=this.db.transaction
						const objectStore = transaction.objectStore(key);
						if(Array.isArray(index)){
							index.forEach(i=>{
								objectStore.deleteIndex(i)
							})
						}else{
							objectStore.deleteIndex(index)
						}
						transaction.oncomplete = () => {
							r(true)
						};
					}catch(err){
						r(false)
					}
				}
			}else{
				r(true)
			}

		})
	}
	async createIndex(table,indexs){
		const temp_db=(await this.getDB())
		return new Promise( async(r,j)=>{
			let db=temp_db
			db.close()
			db=window.indexedDB.open(db.name,db.version+1);
			db.onupgradeneeded = (event) => {
				const newDB = event.target.result;
				this.db=newDB
				try {
					// 创建新的对象存储
					let objectStore
					if(newDB.objectStoreNames.contains(table)){//存在
						objectStore=db.transaction.objectStore(table)
					}else{
						objectStore = newDB.createObjectStore(table);
					}
					// 创建索引
					if (Array.isArray(indexs)) {
						indexs.forEach((index) => {
							if (!objectStore.indexNames.contains(index.name)) {
								// 如果新索引不存在，创建它
								objectStore.createIndex(index.name, index.key || index.name, index.config||{...index});
							}
						});
					}
					// 在事务完成时关闭数据库
					objectStore.transaction.oncomplete = () => {
						r(true);
					};
				} catch (err) {
					j(err);
				}
			}
		})
	}
	find(key,value){
		return new Promise( async r=>{
			const db=(await this.getDB())
			const request = db
			.transaction([key], "readwrite")
			.objectStore(key)
			.get(value);
			request.onsuccess = (event) => {
				r(request.result)
			};
		})
	}
	clear(key){
		return new Promise( async r=>{
			const db=(await this.getDB())
			const request = db
			.transaction([key], "readwrite")
			.objectStore(key)
			.clear();
			request.onsuccess = () => {
				r(true)
			};
			request.onerror = (err) => {
				console.error("clear() err:",err.currentTarget.error);
				r(false)
			};
		})
	}
	count(key){
		return new Promise( async r=>{
			const db=(await this.getDB())
			const request = db
			.transaction([key], "readwrite")
			.objectStore(key)
			.count();
			request.onsuccess = () => {
				r(request.result)
			};
			request.onerror = (err) => {
				console.error("count() err:",err.currentTarget.error);
				r(false)
			};
		})
	}
	findIndex(key,index,value){
		return new Promise( async r=>{
			const db=(await this.getDB())
			const request = db
			.transaction([key], "readwrite")
			.objectStore(key)
			.index(index)
			.get(value);
			request.onsuccess = (event) => {
				r(request.result)
			};
		})
	}
	findIndexAll(key,index,value){
		return new Promise( async r=>{
			const db=(await this.getDB())
			const request = db
			.transaction([key], "readwrite")
			.objectStore(key)
			.index(index)
			.getAll(value);
			request.onsuccess = (event) => {
				r(request.result)
			};
		})
	}
	findAll(key){
		return new Promise( async r=>{
			const db=(await this.getDB())
			const request = db
			.transaction([key], "readwrite")
			.objectStore(key)
			.getAll();
			request.onsuccess = (event) => {
				r(request.result)
			};
		})
	}
	close(){
		return new Promise(r=>{
			if(this.db){
				this.db.close();
				this.db = null;
				r()
			}else{
				r()
			}
		})
	}
}
export default IndexedDB
export {
	IndexedDB
}
// const db = new IndexedDB//创建数据库
// console.log("db:",db);
(async ()=>{
	// console.log("db.setKey):",await db.setKey("a1",{ keyPath: "b3" }));//添加key
	// ###### console.log("db.setKey):",await db.setKey([{key:"a1", config:{ keyPath: "b3" }},{key:"a2", config:{ keyPath: "b4" }}]));
	// console.log("db.push[11,22,33]):",await db.push("names",[1,2]));//添加
	
	// console.log("db.push[11,22,33]):",await db.push("names",[{
	// 	value:"值",
	// 	key:"1"
	// }]));//添加
	// console.log("db.add('names,1,2'):",await db.add('names',1,"/a"));//添加
	// console.log("db.add('names,1,2'):",await db.add('names',2,"/b"));//添加
	// console.log("db.add('names,1,2'):",await db.add('names',3,"/c"));//添加
	// console.log("db.add('names,1,2'):",await db.put('names',1,"/a"));//添加
	// console.log("db.add('names,1,2'):",await db.put('names',2,"/b"));//添加
	// console.log("db.add('names,1,2'):",await db.put('names',3,"/c"));//添加
	/*
	创建表createTable setKey
	添加addcreate
	批量添加push
	更新put
	添加或更新add(,,,true)
	删除
	更新

	*/
	// const obj = { hello: "world" };
	// const blob = new Blob([JSON.stringify(obj, null, 2)], {
	// type: "application/json",
	// });
	
	// console.log("isCreate:",await db.isCreate("names"));//是否创建
	// console.log("createTable:",await db.createTable("names",{autoIncrement: true}));//创建表或者键
	// console.log("db.delete('names,1,2'):",await db.add('names',blob,"/aaa1"));//添加
	// console.log("db.delete('names,1,2'):",await db.add('names',new File([blob],"a.ta"),"/aaa2"));//添加
	// console.log("db.delete('names,1,2'):",await db.push("names",[{//批量添加
	// 	value:"值11",
	// 	key:"1222"
	// },{
	// 	value:"值11",
	// 	key:"1222"
	// }]))
	// const tableName="names";
	// console.log("setKey:",await db.setKey(tableName,{ autoIncrement: true,keyPath:"keyPath" },[{name:"t1",key:"t1", config:{ keyPath: "t" }},{name:"t2",key:"t2", config:{ keyPath: "t" }}]));
	// console.log("add:",await db.add(tableName,{t3:"33334443333"},"a",true));//添加
	// console.log("add:",await db.add(tableName,{t1:1,t2:2,t3:3},"undefined",true));//添加
	// console.log("add:",await db.add(tableName,{aa:12,t1:12,t2:23,t3:31},undefined,true));//添加
	// console.log("add:",await db.add(tableName,{aa:12233,t1:12},undefined,true));//添加
	// console.log("add:",await db.add(tableName,{aa:14,t3:31},undefined,true));//添加
	// console.log("setKey:",await db.setKey(tableName,{ keyPath:"aa",autoIncrement:true }));
	// console.log("add:",await db.add(tableName,{aa:"内键",t1:1,t2:2,t3:3},undefined,true));//添加 内建和外键
	// console.log("add:",await db.add(tableName,blob,"aa",true));//添加 内建和外键
	// console.log("add:",await db.add(tableName,{aa:1,t1:1,t2:2,t3:3},111111,true));//添加
	// console.log("add:",await db.add(tableName,{aa:12,t1:12,t2:23,t3:31},undefined,true));//添加
	// console.log("add:",await db.add(tableName,{aa:12233,t1:12},undefined,true));//添加
	// console.log("add:",await db.add(tableName,{aa:14,t3:31},undefined,true));//添加

	
	// console.log("add:",await db.add(tableName,12222222,undefined,true));//添加
	// console.log("find:",await db.find(tableName,"12222"));//查键
	// console.log("findAll:",await db.findAll(tableName));//全部
	// console.log("delete:",await db.delete(tableName,"12222"));//删除是根据key来删的
	// console.log("findAll:",await db.findAll(tableName));//查全部
	// console.log("db.count:",await db.count(tableName));//有多少数据
	// console.log("db.clear:",await db.clear(tableName));//清除全部
})()
/*
创建了键路径key不能使用 未设置键路径可以设置key和不设置就是add的第三个参数
*/